#include "UdpServer.hpp"
#include <memory>
#include "Thread.hpp"

using namespace ThreadMoudle;

int InitClient()
{
    int sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        std::cerr << "create socket error" << std::endl;
        exit(1);
    }
    return sockfd;
}
// 收消息
void RecvMessage(int sockfd, const std::string &name)
{
    while (true)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof peer;
        char buffer[1024];
        int n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len); // 接收消息 从temp读 len 长度的消息 读到buffer中
        if (n > 0)
        {
            buffer[n] = 0;
            std::cerr << buffer << std::endl;
        }
        else
        {
            std::cerr << "recvfrom error" << std::endl;
            break;
        }
    }
}
// 发消息
void SendMessage(int sockfd, std::string serverip, uint16_t serverport, const std::string &name)
{
    struct sockaddr_in server;
    memset(&server, 0, sizeof server);
    server.sin_family = AF_INET;
    server.sin_port = htons(serverport);
    server.sin_addr.s_addr = inet_addr(serverip.c_str()); // 需要4字节ip 需要网络序列的ip

    std::string cli_profix = name + "# ";
    while (tcgetpgrp)
    {

        std::string line;
        std::cout << cli_profix; // recver-thread#
        std::getline(std::cin, line);

        int n = sendto(sockfd, line.c_str(), line.size(), 0, (struct sockaddr *)&server, sizeof server); // 要知道发给谁
        if (n <= 0)
            break; // 发送失败
    }
}
int main(int argc, char *argv[])
{

    if (argc != 3)
    {
        std::cerr << "Usage: " << argv[0] << "server_ip server_port" << std::endl;
        exit(0);
    }

    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);

    int sockfd = InitClient();
    Thread recver("recver-thread", std::bind(&RecvMessage, sockfd, std::placeholders::_1));                       // 接收线程
    Thread sender("sender-thread", std::bind(&SendMessage, sockfd, serverip, serverport, std::placeholders::_1)); // 发送线程

    recver.Start();
    sender.Start();

    recver.Join();
    sender.Join();
    // 客户端的端口号 一般不让用户自己设定，而是让client os随机选择
    // client不需要显式bing自己的IP地址和端口号
    // client在首次向服务器发送数据的时候，os会自动给client bind他自己的ip地址和端口号


    ::close(sockfd);
    return 0;
}